//--------------------------------------------------------------------------------------//
//                                                                                      //
//    __  __  __    __    __  ___   __   ___  __    ___    __  __  __  ___  ___  __     //
//   / _)/  \(  )  (  )  (  )(   \ (  ) (  ,)(  )  (  _)  (  \/  )/  \(   \(  _)(  )    //
//  ( (_( () ))(__  )(__  )(  ) ) )/__\  ) ,\ )(__  ) _)   )    (( () )) ) )) _) )(__   //
//   \__)\__/(____)(____)(__)(___/(_)(_)(___/(____)(___)  (_/\/\_)\__/(___/(___)(____)  //
//                                                                                      //
//                                                                                      //
//       Copyright by Theodor Mader, 2009                                               //
//			www.theomader.com/public/Projects.html                                      //
//--------------------------------------------------------------------------------------//

#include <stdio.h>
#include "Geometry.h"
#include "BspTree.h"

using namespace Geometry;

// Visual C++ doesn't like hypot as used in jama... replace by _hypot instead
#include <math.h>
#define hypot _hypot

#include "tnt_126/tnt.h"
#include "tnt_126/jama_eig.h"


extern "C"
{
	/*! Computes the biggest eigenvector of \a matrix, returns the vector as individual components in
	*	\a x, \a y, \a z. Computations are performed in double precision.							*/
	__declspec(dllexport) 
	void ComputeBiggestEigenvector( double* matrix, double& x, double& y, double& z )
	{
		// use JAMA to compute eigenvectors and eigenvalues
		TNT::Array2D<double> cMatrix( 3, 3, matrix );
		JAMA::Eigenvalue<double> eig( cMatrix );
	
		TNT::Array1D<double> eigenvalues( 3 );
		TNT::Array2D<double> eigenvectors( 3, 3 );
	
		eig.getRealEigenvalues( eigenvalues );
		eig.getV( eigenvectors );
		
		// get index of biggest eigenvector
		int biggestEvIdx = 0;
		if( eigenvalues[1] > eigenvalues[biggestEvIdx] )
			biggestEvIdx = 1;
		if( eigenvalues[2] > eigenvalues[biggestEvIdx] )
			biggestEvIdx = 2;
	
		// return biggest eigenvector
		x = eigenvectors[0][biggestEvIdx];
		y = eigenvectors[1][biggestEvIdx];
		z = eigenvectors[2][biggestEvIdx];
	}

	/*!	Computes a bsp tree from \a vertices, returns binary representation in a \result
	*	Note: Code assumes that \a vertexData doesn't contain duplicate vertices
	*/
	__declspec(dllexport) 
	bool ComputeCollisionData( float* vertexData, unsigned int dataSize, unsigned int numVerticesPerLeaf, unsigned int numThreads, char*& result, unsigned int& resultSize )
	{
		// convert flat vertex buffer to internally used vertex representation. 
		std::vector<Vertex> vertices( dataSize / 3 );
		unsigned int curVertex = 0;
		for( unsigned int i=0; i<dataSize; i+=3 ) 
		{
			vertices[curVertex] = Vertex( vertexData[i], vertexData[i+1], vertexData[i+2] );
			curVertex++;
		}

		// compute the tree
		BspTree tree( vertices, numVerticesPerLeaf );
		if( numThreads > 1 )
			tree.BuildMT( numThreads );
		else
			tree.Build();

		// allocate space for result data
		resultSize = tree.ComputeRequiredBufferSize();
		result = new char[resultSize];

		// copy to result array
		return tree.SaveToBuffer( result, resultSize );
	}

	__declspec(dllexport) 
	void FreeCollisionData( float* collisionData )
	{
		delete [] collisionData;
	}

}